import axios, { AxiosRequestConfig } from 'axios'
import { getCookie } from '@/utils/auth'
import { ElMessage } from 'element-plus';
import NProgress from 'nprogress';

// 存储请求的标识和对应的取消函数
const pendingAjax = new Map()

// 请求标志
const duplicatedKeyFn = (config: AxiosRequestConfig) => `${config.method}${config.url}${JSON.stringify(config.params)}${JSON.stringify(config.data)}`

/**
 * 将请求添加到pendingAjax
 * @param config
 */
function addPendingAjax(config: AxiosRequestConfig) {
    const duplicatedKey = JSON.stringify({
        duplicatedKey: duplicatedKeyFn(config),
        type: 'DUPLICATED_REQUEST'
    })
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
        if (duplicatedKey && !pendingAjax.has(duplicatedKey)) { // 如果pendingAjax中不存在当前请求，添加进去
            pendingAjax.set(duplicatedKey, cancel)
        }
    })
}

/**
 * 从pendingAjax中删除请求
 * @param config
 */
function removePendingAjax(config: AxiosRequestConfig) {
    const duplicatedKey = JSON.stringify({
        duplicatedKey: duplicatedKeyFn(config),
        type: 'DUPLICATED_REQUEST'
    })
    // 如果pendingAjax中存在当前请求, 取消当前请求并将其删除
    if (duplicatedKey && pendingAjax.has(duplicatedKey)) {
        const cancel = pendingAjax.get(duplicatedKey)
        cancel(duplicatedKey)
        pendingAjax.delete(duplicatedKey)
    }
}

// 创建请求实例
const service = axios.create({
    baseURL: import.meta.env.VITE_BASE_API,
    timeout: 5000,
})
// 请求拦截
service.interceptors.request.use(
    (config) => {
        NProgress.start()
        removePendingAjax(config)
        addPendingAjax(config)

        if (getCookie()) {
            // @ts-ignore
            config.headers['authorization'] = 'Bearer ' + getCookie()
        }

        return config
    },
    error => {
        return Promise.reject(error)
    }
)
// 响应拦截
service.interceptors.response.use(
    response => {
        NProgress.done()
        removePendingAjax(response.config)

        const { status, data } = response
        if (status === 200) {
            const { code, message = 'Error' } = data
            if (code === 200) {
                return data;
            }
            ElMessage.error(message)
            return Promise.reject(new Error(message))

        }
    },
    error => {
        NProgress.done()
        const config = error.config || {}
        removePendingAjax(config)
        // 类型是否为重复请求
        // 取消请求会报错，但不应该返回给用户
        let isDuplicatedType
        try {
            const errorType = (JSON.parse(error.message) || {}).type
            isDuplicatedType = errorType === 'DUPLICATED_REQUEST'
        } catch (error) {
            isDuplicatedType = false
        }
        if (isDuplicatedType) {
            return
        }

        let { status, message } = error
        if (message == 'Network Error') {
            message = '后端接口连接异常'
        } else if (message.includes('timeout')) {
            message = '系统接口请求超时'
        } else if (message.includes('Request failed with status code')) {
            message = '系统接口' + message.substr(message.length - 3) + '异常'
        }
        switch (status) {
            case 400: message = '请求错误'; break
            case 401: message = '未授权，请登录'; break
            case 403: message = '拒绝访问'; break
            case 404: message = '请求地址出错'; break
            case 408: message = '请求超时'; break
            case 500: message = '服务器内部错误'; break
            case 501: message = '服务未实现'; break
            case 502: message = '网关错误'; break
            case 503: message = '服务不可用'; break
            case 504: message = '网关超时'; break
            case 505: message = 'HTTP版本不受支持'; break
            default: break
        }
        ElMessage.error(message)
        return Promise.reject(error)
    }
)

export default service
